#pragma once
#include <sstream>

/* Verbose Debugging Tools */
//#define STRING_ALLOC_DEBUG 1
//#define VALUE_ALLOC_DEBUG 1
//#define SCOPE_ALLOC_DEBUG 1

/* Debugging */
#ifdef BUILT_WITH_DEBUGGING
#define DEBUG_BYTECODE_0(command)				\
	{											\
		AdderString _dbv;						\
		_dbv << command;						\
		this->_debug(_dbv.c_str());				\
	}

#define DEBUG_BYTECODE_1(command, p1)			\
	{											\
		AdderString _dbv;						\
		_dbv << command << " " << p1;			\
		this->_debug(_dbv.c_str());				\
	}

#define DEBUG_BYTECODE_2(command, p1, p2)		\
	{											\
		AdderString _dbv;						\
		_dbv << command << " " << p1			\
						<< " " << p2;			\
		this->_debug(_dbv.c_str());				\
	}

#define DEBUG_BYTECODE_3(command, p1, p2, p3)	\
	{											\
		AdderString _dbv;						\
		_dbv << command << " " << p1			\
						<< " " << p2			\
						<< " " << p3;			\
		this->_debug(_dbv.c_str());				\
	}

#define DEBUG_BYTECODE_4(command, p1, p2, p3, p4)	\
	{												\
		AdderString _dbv;							\
		_dbv << command << " " << p1				\
						<< " " << p2				\
						<< " " << p3				\
						<< " " << p4;				\
		this->_debug(_dbv.c_str());					\
	}
#else
#define DEBUG_BYTECODE_0(command) {}
#define DEBUG_BYTECODE_1(command, p1) {}
#define DEBUG_BYTECODE_2(command, p1, p2) {}
#define DEBUG_BYTECODE_3(command, p1, p2, p3) {}
#define DEBUG_BYTECODE_4(command, p1, p2, p3, p4) {}
#endif
/* Error Throwing */
#define THROW_ERROR_0(command, err)					\
	{												\
		AdderString _dbv;							\
		_dbv << command;							\
		AdderString _tr;							\
		_tr << err;									\
		this->_throwError(_dbv.c_str(),				\
							_tr.c_str());			\
		exit(1);									\
	}

#define THROW_ERROR_1(command, p1, err)				\
	{												\
		AdderString _dbv;							\
		_dbv << command << " " << p1;				\
		AdderString _tr;							\
		_tr << err;									\
		this->_throwError(_dbv.c_str(),				\
							_tr.c_str());			\
		exit(1);									\
	}

#define THROW_ERROR_2(command, p1, p2, err)			\
	{												\
		AdderString _dbv;							\
		_dbv << command << " " << p1				\
						<< " " << p2;				\
		AdderString _tr;							\
		_tr << err;									\
		this->_throwError(_dbv.c_str(),				\
							_tr.c_str());			\
		exit(1);									\
	}

#define THROW_ERROR_3(command, p1, p2, p3, err)		\
	{												\
		AdderString _dbv;							\
		_dbv << command << " " << p1				\
						<< " " << p2				\
						<< " " << p3;				\
		AdderString _tr;							\
		_tr << err;									\
		this->_throwError(_dbv.c_str(),				\
							_tr.c_str());			\
		exit(1);									\
	}

#define THROW_ERROR_4(command, p1, p2, p3, p4, err)	\
	{												\
		AdderString _dbv;							\
		_dbv << command << " " << p1				\
						<< " " << p2				\
						<< " " << p3				\
						<< " " << p4;				\
		AdderString _tr;							\
		_tr << err;									\
		this->_throwError(_dbv.c_str(),				\
							_tr.c_str());			\
		exit(1);									\
	}

/* Breaking (Debugging) */
#define BREAK_CHECK_0(command)						\
	{												\
		if (this->breaking)							\
		{											\
			if (this->debug)						\
			{										\
				AdderString _dbv;					\
				_dbv << command;					\
				this->_breakDebug(_dbv.c_str());	\
			}										\
			return;									\
		}											\
	}

#define BREAK_CHECK_1(command, p1)					\
	{												\
		if (this->breaking)							\
		{											\
			if (this->debug)						\
			{										\
				AdderString _dbv;					\
				_dbv << command << " " << p1;		\
				this->_breakDebug(_dbv.c_str());	\
			}										\
			return;									\
		}											\
	}

#define BREAK_CHECK_2(command, p1, p2)				\
	{												\
		if (this->breaking)							\
		{											\
			if (this->debug)						\
			{										\
				AdderString _dbv;					\
				_dbv << command << " " << p1		\
								<< " " << p2;		\
				this->_breakDebug(_dbv.c_str());	\
			}										\
			return;									\
		}											\
	}

#define BREAK_CHECK_3(command, p1, p2, p3)			\
	{												\
		if (this->breaking)							\
		{											\
			if (this->debug)						\
			{										\
				AdderString _dbv;					\
				_dbv << command << " " << p1		\
								<< " " << p2		\
								<< " " << p3;		\
				this->_breakDebug(_dbv.c_str());	\
			}										\
			return;									\
		}											\
	}

#define BREAK_CHECK_4(command, p1, p2, p3, p4)		\
	{												\
		if (this->breaking)							\
		{											\
			if (this->debug)						\
			{										\
				AdderString _dbv;					\
				_dbv << command << " " << p1		\
								<< " " << p2		\
								<< " " << p3		\
								<< " " << p4;		\
				this->_breakDebug(_dbv.c_str());	\
			}										\
			return;									\
		}											\
	}